<template>
  <div class="ws-table">
    <el-table v-loading="loading"
              :data="tableData"
              @sort-change="sortChange"
              :cell-style="tableStyle[appStore.theme].rowCellStyle"
              :header-cell-style="tableStyle[appStore.theme].headerCellStyle"
              :header-row-style="tableStyle[appStore.theme].headerRowStyle"
              :row-style="tableStyle[appStore.theme].rowStyle"
              v-bind="$attrs">
      <!-- 选择列 -->
      <el-table-column
          v-if="selectVisible"
          align="left"
          :selectable="selectable"
          type="selection"
          width="45"
      />
      <template v-for="(column, index) in columns" :key="index">
        <el-table-column v-if="column.type === 'index'" type="index" :width="column.width || 70" v-bind="column"/>
        <el-table-column v-else-if="column.type === 'slot'" show-overflow-tooltip v-bind="column">
          <template #default="scope">
            <!-- 以列属性名作为名字的具名插槽 -->
            <slot :name="column.prop" :row="scope.row" :index="scope.$index"></slot>
          </template>
        </el-table-column>
        <el-table-column v-else show-overflow-tooltip v-bind="column"/>
      </template>
      <!-- 操作 -->
      <el-table-column v-if="operation" :fixed="operation.fixed" label="操作" :width="operation.width">
        <template #default="scope">
          <template v-if="operation.data?.length>0">
            <el-button link v-for="op in operation.data" :key="op.handle"
                       @click="clickHandle(scope.$index, scope.row, op.handle)" v-bind="op">{{ op.label }}
            </el-button>
          </template>
          <slot name="opera" :row="scope.row" :index="scope.$index"></slot>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页 -->
    <ws-pagination
        v-if="!hiddenPage"
        :limit="pageOpt.pageSize"
        :page="pageOpt.pageNo"
        :total="total"
        :layout="layout"
        @pagination="pagination"
    />
  </div>
</template>

<script setup>
import _ from 'lodash'
import request from '@/utils/request'
import {tableStyle} from '@/utils/globalConst'

defineOptions({
  name: 'WsTable',
})

const appStore = useAppStore()

const props = defineProps({
  columns: {
    type: Array
  },
  url: {
    type: String,
    default: ''
  },
  // 筛选条件
  condition: {
    type: Object,
    default: () => ({})
  },
  // 分页对象
  pageObj: {
    type: Object,
    default: () => ({
      pageNo: 1,
      pageSize: 10
    })
  },
  // 是否外部数据源，不走组件内接口
  isExData: {
    type: Boolean,
    default: false
  },
  // 外部传入的table数据源 不走组件内接口
  exTableData: {
    type: Array,
    default: () => []
  },
  // 外部传入的table总记录数 不走组件内接口
  exTotal: {
    type: Number,
    default: 0
  },
  exLoading: {
    type: Boolean,
    default: false
  },
  // 选择列
  selectVisible: {
    type: Boolean,
    default: false
  },
  // 选中行回调
  selectable: {
    type: Function,
    default: () => {
    }
  },
  // 操作列
  operation: {
    type: Object,
    default: () => null
  },
  layout: {
    type: String,
    default: 'total, sizes, prev, pager, next'
  },
  // 控制分页组件的显示隐藏
  hiddenPage: {
    type: Boolean,
    default: false
  }
})
const emit = defineEmits(['scroll', 'update:page', 'update:limit', 'pagination', 'getTotal', 'update:pageObj', 'selectionChange', 'update:condition', 'sort', 'handleEdit', 'handleDelete'])
const state = reactive({
  tableData: [],
  total: props.exTotal,
  loading: false,
  pageOpt: props.pageObj,
  sortDir: null,
  sortColumn: null
})
const {tableData, total, loading, pageOpt} = toRefs(state)

onMounted(() => {
  // console.log(attrs) // 外部传入的el-table属性
  if (!props.isExData) {
    getTableData() // 内部查询数据
  }
})
/** 获取表格数据的方法
 * 它首先检查配置中的URL是否存在，如果不存在，则发出错误消息
 * 如果URL存在，它会根据请求方法（POST或GET）发送一个网络请求来获取数据
 * 请求成功后，更新表格数据和总记录数，并触发一个事件通知总数的变化
 * 如果发生错误，它会将加载状态设为false
 */
const getTableData = () => {
  if (!props.url) {
    Emessage('error', '🚫url为空!')
    console.error('🚫url为空!')
    return
  }
  state.loading = true
  // 获取实际的请求参数
  const sort = {
    sortColumn: state.sortColumn,
    sortDir: state.sortDir
  }
  const realParams = _.assign(props.condition, sort)
  // 解析URL和请求方法
  const reqOpt = props.url.split('|')
  const [method, url] = reqOpt[1] ? reqOpt : ['post', reqOpt[0]]
  // 根据请求方法确定请求类型
  const reqKey = method.toLowerCase() === 'post' ? 'data' : 'params'
  try {// 发送网络请求
    request({
      url,
      method,
      [reqKey]: {
        ...state.pageOpt,
        ...realParams
      }
    }).then(res => {
      if (res.code === 200) {
        state.loading = false
        // 更新表格数据
        state.tableData = _.cloneDeep(res.data.result) || []
        // 更新总记录数，
        state.total = res.data.total
        // 触发事件通知总数的变化
        emit('getTotal', state.total)
      } else {
        requestError(res)
      }
    })
  } catch (e) {
    console.error(e)
    state.loading = false
  }
}

/**
 * 处理分页事件
 * @param {Object} ev - 分页事件对象，包含页码和每页条数信息
 * @param {number} ev.pageNo - 当前页码
 * @param {number} ev.pageSize - 每页显示的条数
 */
const pagination = (ev) => {
  // 从事件对象中解构出当前页码和每页条数
  const {page, limit} = ev
  // 更新内部的分页配置对象中的页码和每页条数
  state.pageOpt.pageNo = page
  state.pageOpt.pageSize = limit
  // 如果是外部数据源，则不执行内部查询
  if (props.isExData) {
    // 通知外部页码对象变化，用于外部数据源的分页处理
    emit('update:pageObj', state.pageOpt)
    // 触发自定义的分页事件，用于外部对分页数据的处理
    emit('pagination', state.pageOpt)
  } else {
    // 没有外部数据源时，调用方法从内部数据源获取分页数据
    getTableData()
  }
}
const selectionChange = (selections) => {
  emit('selectionChange', selections)
}
/**
 * 处理点击事件的函数
 * @param {number} index - 被点击行的索引
 * @param {Object} row - 被点击行的数据对象
 * @param {string} handle - 事件处理函数的名称（不包含前缀"handle"）
 */
const clickHandle = (index, row, handle) => {
  // 将传入的handle参数首字母大写后，构造出一个特定的事件名称，
  state.handleName = handle.charAt(0).toUpperCase() + handle.slice(1)
  //使用emit方法触发该事件，同时将被点击行的数据对象和索引作为参数传递给事件处理函数
  emit(`handle${state.handleName}`, row, index)
}
// 给元素设置属性
const setAttrs = (opt) => {
  const {...options} = opt
  /* if (!options.align) {
     options.align = 'left'
   }*/
  return {...options}
}
watchEffect(() => {
  if (props.isExData) {
    state.tableData = props.exTableData
    state.total = props.exTotal
    state.loading = props.exLoading
  }
})
watch(() => props.condition, (condition) => {
  const {request} = condition
  if (request) {
    state.pageOpt.pageNum = 1
    getTableData()
  }
  condition['request'] = false
  emit('update:condition', condition)
})
const sortChange = (column) => {
  const {prop, order} = column
  state.sortColumn = prop
  switch (order) {
    case 'ascending':
      state.sortDir = 'ASC'
      break
    case 'descending':
      state.sortDir = 'DESC'
      break
    default:
      state.sortColumn = null
      state.sortDir = null
  }
  if (props.isExData) {
    emit('sort', {sortColumn: state.sortColumn, sortDir: state.sortDir})
  } else {
    getTableData()
  }
}

// 主题样式
const wsTableBg = computed(() => tableStyle[appStore.theme].tableBg)
const wsCellBg = computed(() => tableStyle[appStore.theme].cellBg)
</script>

<style lang="scss" scoped>
.ws-table {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  flex-direction: column;

  :deep(.el-table) {
    --ws-table-bg: v-bind(wsTableBg);
    --ws-cell-bg: v-bind(wsCellBg);
    background: var(--ws-table-bg);

    .cell:empty::before {
      content: '-';
    }

    .el-table__inner-wrapper:before {
      background: transparent; // 最底部的线
    }

    .el-table__body {
      .cell {
        line-height: 30px;
        background: var(--ws-cell-bg);
        width: auto !important;
      }
    }
  }

  :deep(.el-pagination) {
    margin-top: 20px;
    justify-content: right;
  }
}
</style>
